﻿using System;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows;

namespace Gencode.VECore.VectorShape
{
    public class VECPolygon : VECShape
    {
        PathGeometry _definingGeometry;
        /// <summary>
        /// Serializer object description
        /// </summary>
        private const string serLength = "PolyLength";
        private const string serStartPoint = "PolyStartPoint";
        private const string serPoint = "PolyPoint";
        private const string serClosed = "PolyClosed";

        public VECPolygon()
            : this(new Point(0, 0))
        {
        }

        public VECPolygon(Point start)
        {
            _definingGeometry = new PathGeometry();
            
            LineSegment line = new LineSegment(start, true);

            PathSegmentCollection col = new PathSegmentCollection();
            col.Add(line);

            PathFigure fig = new PathFigure(start,col,false);
            _definingGeometry.Figures.Add(fig);

            this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MouseLeftUp);
            //this.Focusable = true;
        }

        protected override Geometry DefiningGeometry
        {
            get
            {
                if (_definingGeometry == null)
                    _definingGeometry = new PathGeometry();
                return _definingGeometry;
            }
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);

            if (Selected)
            {
                Pen p = new Pen(Brushes.Blue, 1);

                drawingContext.DrawEllipse(Brushes.LightBlue, p, _definingGeometry.Figures[0].StartPoint, 2.5, 2.5);

                foreach (PathSegment segment in _definingGeometry.Figures[0].Segments)
                {
                    drawingContext.DrawEllipse(Brushes.LightBlue, p, ((LineSegment)segment).Point, 2.5, 2.5);
                }
            }
        }

        private void MouseLeftUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (CanvasDocument.SelectedToolType == Gencode.VECore.ToolType.SelectionTool)
            {
                if (!Selected)
                {
                    Selected = true;
                }
            }
        }

        public Point StartPoint
        {
            get
            {
                return _definingGeometry.Figures[0].StartPoint;
            }
            set
            {
                _definingGeometry.Figures[0].StartPoint = value;
            }
        }

        public PathSegmentCollection Segments
        {
            get
            {
                return _definingGeometry.Figures[0].Segments;
            }
            set
            {
                _definingGeometry.Figures[0].Segments = value;
            }
        }

        public override VECShape Clone()
        {
            var shape = new VECPolygon();
            shape.StartPoint = this.StartPoint;
            shape.Segments = this.Segments;

            CopyShapeProperies(shape);
            return shape;
        }

        public override bool IntersectsWith(Rect rectangle)
        {
            var rectgeo = new RectangleGeometry(rectangle, 0, 0);
            var det = _definingGeometry.StrokeContainsWithDetail(new Pen(this.Stroke, this.StrokeThickness), rectgeo);

            if (det == IntersectionDetail.FullyContains || det == IntersectionDetail.FullyInside || det == IntersectionDetail.Intersects)
                return true;

            return false;
        }

        public void AddSegment(Point point)
        {
            _definingGeometry.Figures[0].Segments.Add(new LineSegment(point, true));
            this.InvalidateVisual();
        }

        public void JoinEndSegments()
        {
            _definingGeometry.Figures[0].IsClosed = true;
        }

        public override int HandleCount
        {
            get
            {
                return _definingGeometry.Figures[0].Segments.Count + 1;
            }
        }

        public int MaxHandle
        {
            get
            {
                return _definingGeometry.Figures[0].Segments.Count + 1;
            }
        }

        /// <summary>
        /// Get handle point by 1-based number
        /// </summary>
        /// <param name="handleNumber"></param>
        /// <returns></returns>
        public override Point GetHandle(int handleNumber)
        {
            if (handleNumber == 1)
                return _definingGeometry.Figures[0].StartPoint;

            if (handleNumber - 2 >= 0 && handleNumber - 2 <= _definingGeometry.Figures[0].Segments.Count)
                return ((LineSegment)_definingGeometry.Figures[0].Segments[handleNumber-2]).Point;

            return _definingGeometry.Figures[0].StartPoint;
        }

        public override System.Windows.Input.Cursor GetHandleCursor(int handleNumber)
        {
            return System.Windows.Input.Cursors.SizeAll;
        }

        /// <summary>
        /// Hit test.
        /// Return value: -1 - no hit
        ///                0 - hit anywhere
        ///                > 1 - handle number
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public override int HitTest(Point point)
        {
            if (Selected)
            {
                for (int i = 1; i <= HandleCount; i++)
                {
                    if (GetHandleRectangle(i).Contains(point))
                        return i;
                }
            }

            if (PointInObject(point))
                return 0;

            return -1;
        }

        protected override bool PointInObject(Point point)
        {
            return _definingGeometry.FillContains(point);
            //return _definingGeometry.StrokeContains(new Pen(this.Stroke, this.StrokeThickness), point);
        }

        /// <summary>
        /// Move handle to new point (resizing)
        /// </summary>
        /// <param name="point"></param>
        /// <param name="handleNumber"></param>
        public override void MoveHandle(Point point, int handleNumber)
        {
            if (handleNumber - 2 >= 0 && handleNumber - 2 <= _definingGeometry.Figures[0].Segments.Count)
                ((LineSegment)_definingGeometry.Figures[0].Segments[handleNumber -2]).Point = point;
            else if (handleNumber == 1)
                _definingGeometry.Figures[0].StartPoint = point;

            this.InvalidateVisual();

            CallChangedHandler();
        }

        public override void Move(double deltaX, double deltaY)
        {
            StartPoint = new Point(StartPoint.X + deltaX, StartPoint.Y + deltaY);

            foreach (PathSegment segment in _definingGeometry.Figures[0].Segments)
                ((LineSegment)segment).Point = new Point(
                    ((LineSegment)segment).Point.X + deltaX, 
                    ((LineSegment)segment).Point.Y + deltaY);

            this.InvalidateVisual();

            CallMovedHandler();
        }

        public override void SaveToStream(System.Runtime.Serialization.SerializationInfo info, int orderNumber)
        {
            info.AddValue(
                String.Format(System.Globalization.CultureInfo.InvariantCulture,
                "{0}{1}",
                serStartPoint, orderNumber),
                StartPoint);

            info.AddValue(
                String.Format(System.Globalization.CultureInfo.InvariantCulture,
                "{0}{1}",
                serLength, orderNumber),
                Segments.Count);

            int i = 0;
            foreach (LineSegment p in Segments)
            {
                info.AddValue(
                    String.Format(System.Globalization.CultureInfo.InvariantCulture,
                    "{0}{1}-{2}",
                    serPoint, orderNumber, i++),
                    p.Point);
            }

            int cl = 0;
            if (_definingGeometry.Figures[0].IsClosed)
                cl = 1;
            info.AddValue(
                String.Format(System.Globalization.CultureInfo.InvariantCulture,
                "{0}{1}",
                serClosed, orderNumber),
                cl);

            base.SaveToStream(info, orderNumber);
        }

        public override void LoadFromStream(System.Runtime.Serialization.SerializationInfo info, int orderNumber)
        {
            Point point;
            
            StartPoint = (Point)info.GetValue(
                    String.Format(System.Globalization.CultureInfo.InvariantCulture,
                    "{0}{1}",
                    serStartPoint, orderNumber),
                    typeof(Point));

            int n = info.GetInt32(
                String.Format(System.Globalization.CultureInfo.InvariantCulture,
                "{0}{1}",
                serLength, orderNumber));

            for (int i = 0; i < n; i++)
            {
                point = (Point)info.GetValue(
                    String.Format(System.Globalization.CultureInfo.InvariantCulture,
                    "{0}{1}-{2}",
                    serPoint, orderNumber, i),
                    typeof(Point));

                AddSegment(point);
            }

            int cl = info.GetInt32(
                String.Format(System.Globalization.CultureInfo.InvariantCulture,
                "{0}{1}",
                serClosed, orderNumber));

            if (cl == 1)
                _definingGeometry.Figures[0].IsClosed = true;
            else
                _definingGeometry.Figures[0].IsClosed = false;

            base.LoadFromStream(info, orderNumber);
        }
    }
}
